module trig_lookup_mem (
    input wire clk,                    // 系统时钟
    input wire rst_n,                  // 异步复位
    input wire [11:0] angle_phi,       // 方位角 φ (12位，0-4095对应-90°到90°)
    input wire [11:0] angle_theta,     // 俯仰角 θ (12位，0-4095对应-90°到90°)
    output reg [31:0] sin_phi,         // sin(φ) 输出 (Q16.16格式)
    output reg [31:0] cos_phi,         // cos(φ) 输出 (Q16.16格式)
    output reg [31:0] sin_theta,       // sin(θ) 输出 (Q16.16格式)
    output reg [31:0] cos_theta,       // cos(θ) 输出 (Q16.16格式)
    output reg trig_valid              // 输出有效信号
);

// ============================================================================
// 角度转换参数
// ============================================================================
// 12位输入 (0-4095) 对应 -90° 到 90°
// 转换公式: angle_deg = (angle_12bit * 180 / 4096) - 90
// 即: angle_deg = (angle_12bit * 45 / 1024) - 90
// 
// 中点值: 2048 对应 0°
// 0 对应 -90°
// 4095 对应约 89.956°

// 查找表存储器（0-90度，步进1度）
// 使用Q16.16定点数格式存储
reg [31:0] sin_table [0:90];
reg [31:0] cos_table [0:90];

// 内部寄存器
reg signed [8:0] phi_degree;       // φ角度值（-90到90）
reg signed [8:0] theta_degree;     // θ角度值（-90到90）
reg phi_sign;                      // φ符号位（0=正，1=负）
reg theta_sign;                    // θ符号位（0=正，1=负）
reg [6:0] phi_lookup_angle;        // φ查表角度（0-90）
reg [6:0] theta_lookup_angle;      // θ查表角度（0-90）

// 状态机
reg [1:0] state;
localparam IDLE   = 2'b00;
localparam LOOKUP = 2'b01;
localparam ADJUST = 2'b10;
localparam VALID  = 2'b11;

// 初始化三角函数查找表（0-90度）
initial begin
    // sin值 (Q16.16格式，值范围0到65536对应0到1)
    sin_table[0]  = 32'h00000000;  // sin(0°)  = 0.0000
    sin_table[1]  = 32'h000477D1;  // sin(1°)  = 0.0175
    sin_table[2]  = 32'h0008EFA3;  // sin(2°)  = 0.0349
    sin_table[3]  = 32'h000D6764;  // sin(3°)  = 0.0523
    sin_table[4]  = 32'h0011DF0E;  // sin(4°)  = 0.0698
    sin_table[5]  = 32'h00165692;  // sin(5°)  = 0.0872
    sin_table[6]  = 32'h001ACDE9;  // sin(6°)  = 0.1045
    sin_table[7]  = 32'h001F450B;  // sin(7°)  = 0.1219
    sin_table[8]  = 32'h0023BBF7;  // sin(8°)  = 0.1392
    sin_table[9]  = 32'h002832A8;  // sin(9°)  = 0.1564
    sin_table[10] = 32'h002CA916;  // sin(10°) = 0.1736
    sin_table[11] = 32'h00311F40;  // sin(11°) = 0.1908
    sin_table[12] = 32'h00359525;  // sin(12°) = 0.2079
    sin_table[13] = 32'h003A0AC4;  // sin(13°) = 0.2250
    sin_table[14] = 32'h003E801F;  // sin(14°) = 0.2419
    sin_table[15] = 32'h0042F534;  // sin(15°) = 0.2588
    sin_table[16] = 32'h00476A07;  // sin(16°) = 0.2756
    sin_table[17] = 32'h004BDE97;  // sin(17°) = 0.2924
    sin_table[18] = 32'h005052E6;  // sin(18°) = 0.3090
    sin_table[19] = 32'h0054C6F3;  // sin(19°) = 0.3256
    sin_table[20] = 32'h00593ABF;  // sin(20°) = 0.3420
    sin_table[21] = 32'h005DAE4A;  // sin(21°) = 0.3584
    sin_table[22] = 32'h00622194;  // sin(22°) = 0.3746
    sin_table[23] = 32'h0066949E;  // sin(23°) = 0.3907
    sin_table[24] = 32'h006B0768;  // sin(24°) = 0.4067
    sin_table[25] = 32'h006F79F2;  // sin(25°) = 0.4226
    sin_table[26] = 32'h0073EC3C;  // sin(26°) = 0.4384
    sin_table[27] = 32'h00785E47;  // sin(27°) = 0.4540
    sin_table[28] = 32'h007CD013;  // sin(28°) = 0.4695
    sin_table[29] = 32'h0081419F;  // sin(29°) = 0.4848
    sin_table[30] = 32'h0085B2EC;  // sin(30°) = 0.5000
    sin_table[31] = 32'h008A23FA;  // sin(31°) = 0.5150
    sin_table[32] = 32'h008E94C9;  // sin(32°) = 0.5299
    sin_table[33] = 32'h00930559;  // sin(33°) = 0.5446
    sin_table[34] = 32'h009775AA;  // sin(34°) = 0.5592
    sin_table[35] = 32'h009BE5BD;  // sin(35°) = 0.5736
    sin_table[36] = 32'h00A05591;  // sin(36°) = 0.5878
    sin_table[37] = 32'h00A4C526;  // sin(37°) = 0.6018
    sin_table[38] = 32'h00A9347D;  // sin(38°) = 0.6157
    sin_table[39] = 32'h00ADA395;  // sin(39°) = 0.6293
    sin_table[40] = 32'h00B2126E;  // sin(40°) = 0.6428
    sin_table[41] = 32'h00B68109;  // sin(41°) = 0.6561
    sin_table[42] = 32'h00BAEF65;  // sin(42°) = 0.6691
    sin_table[43] = 32'h00BF5D82;  // sin(43°) = 0.6820
    sin_table[44] = 32'h00C3CB60;  // sin(44°) = 0.6947
    sin_table[45] = 32'h00C838FF;  // sin(45°) = 0.7071
    sin_table[46] = 32'h00CCA65E;  // sin(46°) = 0.7193
    sin_table[47] = 32'h00D1137E;  // sin(47°) = 0.7314
    sin_table[48] = 32'h00D5805E;  // sin(48°) = 0.7431
    sin_table[49] = 32'h00D9ECFF;  // sin(49°) = 0.7547
    sin_table[50] = 32'h00DE5960;  // sin(50°) = 0.7660
    sin_table[51] = 32'h00E2C581;  // sin(51°) = 0.7771
    sin_table[52] = 32'h00E73162;  // sin(52°) = 0.7880
    sin_table[53] = 32'h00EB9D03;  // sin(53°) = 0.7986
    sin_table[54] = 32'h00F00864;  // sin(54°) = 0.8090
    sin_table[55] = 32'h00F47384;  // sin(55°) = 0.8192
    sin_table[56] = 32'h00F8DE65;  // sin(56°) = 0.8290
    sin_table[57] = 32'h00FD4905;  // sin(57°) = 0.8387
    sin_table[58] = 32'h0101B364;  // sin(58°) = 0.8480
    sin_table[59] = 32'h01061D83;  // sin(59°) = 0.8572
    sin_table[60] = 32'h010A8762;  // sin(60°) = 0.8660
    sin_table[61] = 32'h010EF100;  // sin(61°) = 0.8746
    sin_table[62] = 32'h01135A5E;  // sin(62°) = 0.8829
    sin_table[63] = 32'h0117C37C;  // sin(63°) = 0.8910
    sin_table[64] = 32'h011C2C59;  // sin(64°) = 0.8988
    sin_table[65] = 32'h012094F6;  // sin(65°) = 0.9063
    sin_table[66] = 32'h0124FD52;  // sin(66°) = 0.9135
    sin_table[67] = 32'h0129656E;  // sin(67°) = 0.9205
    sin_table[68] = 32'h012DCD49;  // sin(68°) = 0.9272
    sin_table[69] = 32'h013234E4;  // sin(69°) = 0.9336
    sin_table[70] = 32'h01369C3E;  // sin(70°) = 0.9397
    sin_table[71] = 32'h013B0357;  // sin(71°) = 0.9455
    sin_table[72] = 32'h013F6A31;  // sin(72°) = 0.9511
    sin_table[73] = 32'h0143D0C9;  // sin(73°) = 0.9563
    sin_table[74] = 32'h01483721;  // sin(74°) = 0.9613
    sin_table[75] = 32'h014C9D38;  // sin(75°) = 0.9659
    sin_table[76] = 32'h0151030F;  // sin(76°) = 0.9703
    sin_table[77] = 32'h015568A5;  // sin(77°) = 0.9744
    sin_table[78] = 32'h0159CDFA;  // sin(78°) = 0.9781
    sin_table[79] = 32'h015E330F;  // sin(79°) = 0.9816
    sin_table[80] = 32'h016297E3;  // sin(80°) = 0.9848
    sin_table[81] = 32'h0166FC76;  // sin(81°) = 0.9877
    sin_table[82] = 32'h016B60C8;  // sin(82°) = 0.9903
    sin_table[83] = 32'h016FC4D9;  // sin(83°) = 0.9925
    sin_table[84] = 32'h017428A9;  // sin(84°) = 0.9945
    sin_table[85] = 32'h01788C38;  // sin(85°) = 0.9962
    sin_table[86] = 32'h017CEF86;  // sin(86°) = 0.9976
    sin_table[87] = 32'h01815293;  // sin(87°) = 0.9986
    sin_table[88] = 32'h0185B55F;  // sin(88°) = 0.9994
    sin_table[89] = 32'h018A17EA;  // sin(89°) = 0.9998
    sin_table[90] = 32'h018E7A34;  // sin(90°) = 1.0000

    // cos值 (Q16.16格式)
    cos_table[0]  = 32'h00010000;  // cos(0°)  = 1.0000
    cos_table[1]  = 32'h0000FFFF;  // cos(1°)  = 0.9998
    cos_table[2]  = 32'h0000FFFA;  // cos(2°)  = 0.9994
    cos_table[3]  = 32'h0000FFF1;  // cos(3°)  = 0.9986
    cos_table[4]  = 32'h0000FFE4;  // cos(4°)  = 0.9976
    cos_table[5]  = 32'h0000FFD3;  // cos(5°)  = 0.9962
    cos_table[6]  = 32'h0000FFBD;  // cos(6°)  = 0.9945
    cos_table[7]  = 32'h0000FFA4;  // cos(7°)  = 0.9925
    cos_table[8]  = 32'h0000FF86;  // cos(8°)  = 0.9903
    cos_table[9]  = 32'h0000FF64;  // cos(9°)  = 0.9877
    cos_table[10] = 32'h0000FF3D;  // cos(10°) = 0.9848
    cos_table[11] = 32'h0000FF13;  // cos(11°) = 0.9816
    cos_table[12] = 32'h0000FEE4;  // cos(12°) = 0.9781
    cos_table[13] = 32'h0000FEB1;  // cos(13°) = 0.9744
    cos_table[14] = 32'h0000FE7A;  // cos(14°) = 0.9703
    cos_table[15] = 32'h0000FE3F;  // cos(15°) = 0.9659
    cos_table[16] = 32'h0000FDFF;  // cos(16°) = 0.9613
    cos_table[17] = 32'h0000FDBC;  // cos(17°) = 0.9563
    cos_table[18] = 32'h0000FD74;  // cos(18°) = 0.9511
    cos_table[19] = 32'h0000FD28;  // cos(19°) = 0.9455
    cos_table[20] = 32'h0000FCD7;  // cos(20°) = 0.9397
    cos_table[21] = 32'h0000FC82;  // cos(21°) = 0.9336
    cos_table[22] = 32'h0000FC29;  // cos(22°) = 0.9272
    cos_table[23] = 32'h0000FBCC;  // cos(23°) = 0.9205
    cos_table[24] = 32'h0000FB6B;  // cos(24°) = 0.9135
    cos_table[25] = 32'h0000FB05;  // cos(25°) = 0.9063
    cos_table[26] = 32'h0000FA9C;  // cos(26°) = 0.8988
    cos_table[27] = 32'h0000FA2E;  // cos(27°) = 0.8910
    cos_table[28] = 32'h0000F9BD;  // cos(28°) = 0.8829
    cos_table[29] = 32'h0000F947;  // cos(29°) = 0.8746
    cos_table[30] = 32'h0000F8CE;  // cos(30°) = 0.8660
    cos_table[31] = 32'h0000F850;  // cos(31°) = 0.8572
    cos_table[32] = 32'h0000F7CE;  // cos(32°) = 0.8480
    cos_table[33] = 32'h0000F748;  // cos(33°) = 0.8387
    cos_table[34] = 32'h0000F6BE;  // cos(34°) = 0.8290
    cos_table[35] = 32'h0000F630;  // cos(35°) = 0.8192
    cos_table[36] = 32'h0000F59E;  // cos(36°) = 0.8090
    cos_table[37] = 32'h0000F508;  // cos(37°) = 0.7986
    cos_table[38] = 32'h0000F46E;  // cos(38°) = 0.7880
    cos_table[39] = 32'h0000F3D1;  // cos(39°) = 0.7771
    cos_table[40] = 32'h0000F32F;  // cos(40°) = 0.7660
    cos_table[41] = 32'h0000F28A;  // cos(41°) = 0.7547
    cos_table[42] = 32'h0000F1E1;  // cos(42°) = 0.7431
    cos_table[43] = 32'h0000F134;  // cos(43°) = 0.7314
    cos_table[44] = 32'h0000F083;  // cos(44°) = 0.7193
    cos_table[45] = 32'h0000EFCF;  // cos(45°) = 0.7071
    cos_table[46] = 32'h0000EF17;  // cos(46°) = 0.6947
    cos_table[47] = 32'h0000EE5B;  // cos(47°) = 0.6820
    cos_table[48] = 32'h0000ED9C;  // cos(48°) = 0.6691
    cos_table[49] = 32'h0000ECD9;  // cos(49°) = 0.6561
    cos_table[50] = 32'h0000EC13;  // cos(50°) = 0.6428
    cos_table[51] = 32'h0000EB49;  // cos(51°) = 0.6293
    cos_table[52] = 32'h0000EA7C;  // cos(52°) = 0.6157
    cos_table[53] = 32'h0000E9AB;  // cos(53°) = 0.6018
    cos_table[54] = 32'h0000E8D6;  // cos(54°) = 0.5878
    cos_table[55] = 32'h0000E7FE;  // cos(55°) = 0.5736
    cos_table[56] = 32'h0000E722;  // cos(56°) = 0.5592
    cos_table[57] = 32'h0000E643;  // cos(57°) = 0.5446
    cos_table[58] = 32'h0000E560;  // cos(58°) = 0.5299
    cos_table[59] = 32'h0000E479;  // cos(59°) = 0.5150
    cos_table[60] = 32'h0000E38F;  // cos(60°) = 0.5000
    cos_table[61] = 32'h0000E2A2;  // cos(61°) = 0.4848
    cos_table[62] = 32'h0000E1B1;  // cos(62°) = 0.4695
    cos_table[63] = 32'h0000E0BC;  // cos(63°) = 0.4540
    cos_table[64] = 32'h0000DFC4;  // cos(64°) = 0.4384
    cos_table[65] = 32'h0000DEC8;  // cos(65°) = 0.4226
    cos_table[66] = 32'h0000DDC9;  // cos(66°) = 0.4067
    cos_table[67] = 32'h0000DCC6;  // cos(67°) = 0.3907
    cos_table[68] = 32'h0000DBBF;  // cos(68°) = 0.3746
    cos_table[69] = 32'h0000DAB5;  // cos(69°) = 0.3584
    cos_table[70] = 32'h0000D9A8;  // cos(70°) = 0.3420
    cos_table[71] = 32'h0000D897;  // cos(71°) = 0.3256
    cos_table[72] = 32'h0000D782;  // cos(72°) = 0.3090
    cos_table[73] = 32'h0000D66A;  // cos(73°) = 0.2924
    cos_table[74] = 32'h0000D54E;  // cos(74°) = 0.2756
    cos_table[75] = 32'h0000D42F;  // cos(75°) = 0.2588
    cos_table[76] = 32'h0000D30D;  // cos(76°) = 0.2419
    cos_table[77] = 32'h0000D1E7;  // cos(77°) = 0.2250
    cos_table[78] = 32'h0000D0BD;  // cos(78°) = 0.2079
    cos_table[79] = 32'h0000CF90;  // cos(79°) = 0.1908
    cos_table[80] = 32'h0000CE60;  // cos(80°) = 0.1736
    cos_table[81] = 32'h0000CD2C;  // cos(81°) = 0.1564
    cos_table[82] = 32'h0000CBF4;  // cos(82°) = 0.1392
    cos_table[83] = 32'h0000CAB9;  // cos(83°) = 0.1219
    cos_table[84] = 32'h0000C97B;  // cos(84°) = 0.1045
    cos_table[85] = 32'h0000C839;  // cos(85°) = 0.0872
    cos_table[86] = 32'h0000C6F3;  // cos(86°) = 0.0698
    cos_table[87] = 32'h0000C5AA;  // cos(87°) = 0.0523
    cos_table[88] = 32'h0000C45D;  // cos(88°) = 0.0349
    cos_table[89] = 32'h0000C30D;  // cos(89°) = 0.0175
    cos_table[90] = 32'h0000C1B9;  // cos(90°) = 0.0000
end

// ============================================================================
// 角度转换和查找表地址计算
// ============================================================================
always @(*) begin
    // 将12位输入转换为角度（-90°到90°）
    // 公式: angle_deg = (input * 180 / 4096) - 90
    // 简化: angle_deg = (input * 45 / 1024) - 90
    // 为了避免除法，使用近似: (input >> 5) - 64 约等于 (input / 32) - 64
    // 更精确方法: (input * 45) >> 10 - 90
    
    // φ角度转换
    phi_degree = ($signed({1'b0, angle_phi}) * 45) >>> 10;  // 先乘45再右移10位
    phi_degree = phi_degree - 90;  // 减去90得到-90到90的范围
    
    // θ角度转换
    theta_degree = ($signed({1'b0, angle_theta}) * 45) >>> 10;
    theta_degree = theta_degree - 90;
    
    // 判断符号并转换到0-90度用于查表
    if (phi_degree < 0) begin
        phi_sign = 1'b1;  // 负数
        phi_lookup_angle = -phi_degree;  // 取绝对值
    end else begin
        phi_sign = 1'b0;  // 正数
        phi_lookup_angle = phi_degree;
    end
    
    if (theta_degree < 0) begin
        theta_sign = 1'b1;  // 负数
        theta_lookup_angle = -theta_degree;  // 取绝对值
    end else begin
        theta_sign = 1'b0;  // 正数
        theta_lookup_angle = theta_degree;
    end
    
    // 限制查表角度在0-90范围内
    if (phi_lookup_angle > 90)
        phi_lookup_angle = 90;
    if (theta_lookup_angle > 90)
        theta_lookup_angle = 90;
end

// ============================================================================
// 主状态机
// ============================================================================
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        sin_phi <= 32'b0;
        cos_phi <= 32'b0;
        sin_theta <= 32'b0;
        cos_theta <= 32'b0;
        trig_valid <= 1'b0;
    end else begin
        case (state)
            IDLE: begin
                trig_valid <= 1'b0;
                state <= LOOKUP;
            end
            
            LOOKUP: begin
                // 从查找表读取绝对值
                sin_phi <= sin_table[phi_lookup_angle];
                cos_phi <= cos_table[phi_lookup_angle];
                sin_theta <= sin_table[theta_lookup_angle];
                cos_theta <= cos_table[theta_lookup_angle];
                state <= ADJUST;
            end
            
            ADJUST: begin
                // 根据符号调整
                // sin(-x) = -sin(x)
                // cos(-x) = cos(x)
                
                if (phi_sign) begin
                    sin_phi <= ~sin_phi + 1;  // 负角度，sin取负
                    // cos保持正值
                end
                
                if (theta_sign) begin
                    sin_theta <= ~sin_theta + 1;  // 负角度，sin取负
                    // cos保持正值
                end
                
                state <= VALID;
            end
            
            VALID: begin
                trig_valid <= 1'b1;
                state <= IDLE;
            end
            
            default: begin
                state <= IDLE;
            end
        endcase
    end
end

endmodule